package com.ruixi.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/*
	动态代理:JDK动态代理
		帮助任何一个有接口的被代理对象获取其代理对象并实现相应功能,注意一定是要有接口的,这作为参数的一部分

	JDK动态代理和CJLIB动态代理的区别
		JDK动态代理是通过创建接口实现类代理对象,增加类的方法
        CJLIB动态代理由于没有接口,所以是通过创建子类的代理对象,增加类的方法
 */
public class ProxyUtil {

	//被代理对象,一般使用Object类型
	private MathImpl mathImpl;

	public ProxyUtil(MathImpl mathImpl) {
		this.mathImpl = mathImpl;
	}

	//获取代理对象并实现相应功能
	public Object getProxy(){

		//类加载器:动态生成的代理对象也是依赖于类存在的,即也是类的实例,所以实际上是生成了动态代理类,类如果想加载必须依赖于类加载器,所以需要指定一个能够加载代理类的加载器
		ClassLoader loader = this.getClass().getClassLoader();

		//获取目标对象实现的所有的接口的class对象,代理类会和目标类实现相同的接口,最终通过代理对象实现功能
		Class[] interfaces = mathImpl.getClass().getInterfaces();

		return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {

			//代理对象实现功能的方式
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				try{
					System.out.println("动态代理之前的操作");
					MyLogger.before(method.getName(), Arrays.toString(args));
					Object result = method.invoke(mathImpl, args);//动态代理对象实现原有功能,args为参数,因为重载,可能有同名不同参的方法,所以方法名加上形参才能确定到具体的方法
					System.out.println(result);
					System.out.println("动态代理之后的操作");
					MyLogger.after(method.getName(),result);
					return result;//确保结果是一致的,所以将方法调用的结果返回
				}catch (Exception e){
					MyLogger.throwing();
					e.printStackTrace();
				}finally {
					System.out.println("哪儿都有我");
				}
				return null;
			}
		});
	}

}
